TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import { z } from "zod";2import { withUser, json, parseBody } from "@/lib/api";3import { getFile, updateFile, deleteFile, toPublicFile } from "@/lib/library/service";45export const dynamic = "force-dynamic";67type P = { id: string };89/**10 * GET /api/library/files/:id — streams the payload to its owner (image previews, downloads).11 * `?meta=1` returns the metadata JSON instead; `?download=1` forces an attachment disposition.12 */13export const GET = withUser<P>(async ({ req, user }, { id }) => {14 const p = new URL(req.url).searchParams;15 const row = await getFile(user.id, id);16 if (p.get("meta") === "1") return json({ file: toPublicFile(row) });17 const buf = Buffer.from(row.dataBase64, "base64");18 const disposition = p.get("download") === "1" ? "attachment" : "inline";19 return new Response(buf, {20 headers: {21 "Content-Type": row.mimeType,22 "Content-Length": String(buf.length),23 "Cache-Control": "private, max-age=3600",24 "Content-Disposition": `${disposition}; filename="${encodeURIComponent(row.name)}"`,25 "X-Content-Type-Options": "nosniff",26 },27 });28});2930const patchSchema = z.object({31 name: z.string().min(1).max(200).optional(),32 description: z.string().max(500).nullable().optional(),33 /** Move to a project, or `null` for the global library. */34 projectId: z.string().max(64).nullable().optional(),35});3637export const PATCH = withUser<P>(async ({ req, user }, { id }) => {38 const body = await parseBody(req, patchSchema);39 return json({ file: await updateFile(user.id, id, body) });40});4142export const DELETE = withUser<P>(async ({ user }, { id }) => {43 await deleteFile(user.id, id);44 return json({ ok: true });45});46